﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using CodeCounsel.SharePoint.DevTools.Commands;
using Microsoft.VisualStudio.SharePoint;
using Microsoft.VisualStudio.SharePoint.Deployment;
using Microsoft.VisualStudio.SharePoint.Packages;

namespace CodeCounsel.SharePoint.DevTools.DeploymentSteps
{
    [Export(typeof(IDeploymentStep))]
    [DeploymentStep(DeploymentStepIds.CopyAssemblies)]
    public class CopyAssemblies
        : IDeploymentStep
    {
        public void Initialize(IDeploymentStepInfo stepInfo)
        {
            stepInfo.Name = "Copy Assemblies";
            stepInfo.StatusBarMessage = "Copying Assemblies...";
            stepInfo.Description = "Copies packaged assemblies to all Web Application folders and to the Global Assembly Cache depending on the assembly deployment type.";
        }

        public bool CanExecute(IDeploymentContext context)
        { 
            bool canExecute = context.Project.IsSandboxedSolution == false;
            if (canExecute == false)
            {
                context.Logger.WriteLine("Skipping step because the project is configured to deploy into the solution sandbox.", LogCategory.Status);
            }
            return canExecute;
        }

        public void Execute(IDeploymentContext context)
        {
            string[] binPaths = context.Project.SharePointConnection.ExecuteCommand<string[]>(CommandIDs.GetWebApplicationFolders);

            IPackage package = context.Project.Package.Model;

            foreach (ISharePointProject project in context.Project.Package.ProjectItems
                .Select(item => item.Project)
                .Distinct())
            {
                TryInstallProjectAssembly(binPaths, project);
            }
            foreach (IAssembly assembly in package.Assemblies)
            {
                string sourcePath = null;
                AssemblyDeploymentTarget deploymentTarget = AssemblyDeploymentTarget.GlobalAssemblyCache;
                ICustomAssembly customAssembly = assembly as ICustomAssembly;
                if (customAssembly != null)
                {
                    sourcePath = customAssembly.Location;
                    deploymentTarget = (AssemblyDeploymentTarget)Enum.Parse(typeof(AssemblyDeploymentTarget), customAssembly.DeploymentTarget.ToString());
                }
                else
                {
                    sourcePath = context.Project.OutputFullPath;
                    deploymentTarget = context.Project.AssemblyDeploymentTarget;
                }
                InstallAssemblyItem(binPaths, sourcePath, deploymentTarget);
            }
        }

        void TryInstallProjectAssembly(string[] binPaths, ISharePointProject project)
        {
            if (project.IncludeAssemblyInPackage)
            {
                InstallAssemblyItem(binPaths, 
                    project.OutputFullPath, 
                    project.AssemblyDeploymentTarget);
            }
        }

        void InstallAssemblyItem(string[] binPaths, string sourcePath, AssemblyDeploymentTarget deploymentTarget)
        {
            if (deploymentTarget == AssemblyDeploymentTarget.GlobalAssemblyCache)
            {
                FusionInstall.AddAssemblyToCache(sourcePath);
            }
            else
            {
                foreach (string binPath in binPaths)
                {
                    string targetPath = Path.Combine(
                        binPath, "bin");
                    if (Directory.Exists(targetPath) == false)
                    {
                        Directory.CreateDirectory(targetPath);
                    }
                    targetPath = Path.Combine(targetPath,
                        Path.GetFileName(sourcePath));
                    File.Copy(sourcePath, targetPath, true);
                }
            }
        }
    }
}
